/******************************************************************************
;  Project:  simon.c
;  Author:   Brady Eisert, Tyler Hale, Keith Thompson is awesome, Fall2012a
;
;  Description: A MSP430 assembly language program that plays the game of Simon.
;
;    1. Each round of the game starts by the LEDs flashing several times.
;    2. The colored LEDs (along with the associated tones) then flash one at
;       a time in a random sequence.
;    3. The push button switches are sampled and compared with the original
;       sequence of colors/tones.
;    4. The sampling the switches continues until the end of the sequence is
;       successfully reached or a mistake is made.
;    5. Some congratulatory tune is played if the sequence is correct or some
;       raspberry sound is output if a mistake is made.
;    6. If the complete sequence is successfully reproduced, the game is
;       repeated with one additional color/tone added to the sequence.
;       Otherwise, the game starts over with the default number of colors/tones.
;
;  Requirements:
;        Timer_B output (TB2) is used for hardware PWM of the transducer (buzzer).
;        Subroutines in at least one assembly and one C file are used by your program.
;        ALL subroutines must be correctly implemented using Callee-Save protocol.
;
;  Bonus:
;
;      -Port 1 interrupts are used to detect a depressed switch.
;       -Use LCD to display round, score, highest score, and lowest score.
;       -Turn on LCD backlight with any activity.
;       -Turn off LCD backlight after 5 seconds of inactivity.
;
;*******************************************************************************/
//
//                            MSP430F2274
//                  .-----------------------------.
//            SW1-->|P1.0^                    P2.0|<->LCD_DB0
//            SW2-->|P1.1^                    P2.1|<->LCD_DB1
//            SW3-->|P1.2^                    P2.2|<->LCD_DB2
//            SW4-->|P1.3^                    P2.3|<->LCD_DB3
//       ADXL_INT-->|P1.4                     P2.4|<->LCD_DB4
//        AUX INT-->|P1.5                     P2.5|<->LCD_DB5
//        SERVO_1<--|P1.6 (TA1)               P2.6|<->LCD_DB6
//        SERVO_2<--|P1.7 (TA2)               P2.7|<->LCD_DB7
//                  |                             |
//         LCD_A0<--|P3.0                     P4.0|-->LED_1 (Green)
//        i2c_SDA<->|P3.1 (UCB0SDA)     (TB1) P4.1|-->LED_2 (Orange) / SERVO_3
//        i2c_SCL<--|P3.2 (UCB0SCL)     (TB2) P4.2|-->LED_3 (Yellow) / SERVO_4
//         LCD_RW<--|P3.3                     P4.3|-->LED_4 (Red)
//   TX/LED_5 (G)<--|P3.4 (UCA0TXD)     (TB1) P4.4|-->LCD_BL
//             RX-->|P3.5 (UCA0RXD)     (TB2) P4.5|-->SPEAKER
//           RPOT-->|P3.6 (A6)          (A15) P4.6|-->LED 6 (R)
//           LPOT-->|P3.7 (A7)                P4.7|-->LCD_E
//                  '-----------------------------'
//
//******************************************************************************
// includes
#include "msp430x22x4.h"
#include <stdlib.h>
#include "RBX430-1.h"
//------------------------------------------------------------------------------
//            NOTE: LOOK in RBX430.h for some macros to use
//------------------------------------------------------------------------------
// defined constants
#define    myCLOCK       1200000            // 1.2 Mhz clock
#define    WDT_CTL       WDT_MDLY_32        // WD configuration (Timer, SMCLK, ~32 ms)
#define    WDT_CPI       32000            // WDT Clocks Per Interrupt (@1 Mhz)
#define    WDT_IPS       myCLOCK/WDT_CPI    // WDT counts/second (32 ms)

#define    TONE          2000                // beep frequency
#define    DELAY         20            // beep duration

#define    R_LED		0x08
#define    Y_LED		0x04
#define    O_LED		0x02
#define    G_LED		0x01

#define    NOTE_Af		2408*8
#define    NOTE_Ef		1607*8
#define    NOTE_Bf		2145*8
#define    NOTE_F		1432*8
#define    NOTE_G		1276*8
#define    NOTE_Afh		1204*8
#define    NOTE_C		1911*8

#define    Rasp1		3000*8
#define	   Rasp2		3300*8
#define    R_SND		2620*8
#define    Y_SND		2940*8
#define    O_SND		3300*8
#define    G_SND		3490*8

enum LedColor { RED=3, YELLOW=2, ORANGE=1, GREEN=0 } LED_COLOR;

//-----------------------------------------------------------
//    external/internal prototypes
extern int rand16(void);                // get random #
extern int setrandSeed(int toSet);
extern int getrandSeed(void);
int getSwitch(void);                    // get switch pressed
void Play_Tone(uint16 tone);                  // Turn on Tone
void toneOFF(void);                        // Turn off Tone
void delay (void);                        // Start delay of program
void Turn_ON_LED (int number);                    // Set the leds based on the number passed in
void Play_Sound_and_LED(int color);
void PlayBeginningSequence(void);
void PlayRaspberrySound(void);
void DelayCustom(int length);
void StartGame(int seed, int sequence_length);
int ReadValues(int seed, int sequence_length);
int VerifyCorrect(int number, int switchLED);
void PlayGame(int seed, int sequence_length);
void Play_Sound_and_LED(int);
void Fanfare(void);

//-----------------------------------------------------------
//    global variables
volatile int WDTSecCnt;                // WDT second counter
volatile int WDT_Delay;                    // WDT delay counter

//-----------------------------------------------------------


int seed = 10;
int lengthSequence = 3;
int LCD_BKLT;

void main(void) {
    RBX430_init(_8MHZ);                    // init board

// Configure the Watchdog
    WDTCTL = WDT_CTL;                    // Set Watchdog interval
    WDTSecCnt = WDT_IPS;                // set WD 1 second counter
    WDT_Delay = 0;                        // reset delay counter
    IE1 |= WDTIE;                        // enable WDT interrupt

    TBR = 0;                            //Timer B SMCLK, /1, up mode
    TBCTL= TBSSEL_2|ID_0|MC_1;            //
    TBCCTL2 = OUTMOD_3;                 // output mode = set/reset
    P4DIR |= 0x2f;                         // P4.5 output (buzzer)
    P4SEL |= 0x20;                        // select alternate output (TB2) for P4.5

    __bis_SR_register(GIE);                // enable interrupts


	//Play opening theme
    PlayBeginningSequence();
	P4OUT &= 0xf0;
    PlayGame(rand16(), 3);
}

void PlayGame(int seed, int sequence_length)
{

	//Output values
	StartGame(seed, sequence_length);
	//read values

	//   if(correct)
	//       play victory, add one to sequence, repeat
	//   else
	//       rasberry, start over
	if(ReadValues(seed, sequence_length))
	{
		//PLAY VICTORY TUNE
		Fanfare();
		P4OUT &= 0xf0;

		//Add one to sequence
		sequence_length++;

		//repeat
		DelayCustom(10);
		PlayGame(seed, sequence_length);
	}
	else
	{
		PlayRaspberrySound();

		//Play opening theme
		DelayCustom(10);
	    PlayBeginningSequence();
		P4OUT &= 0xf0;
		PlayGame(rand16(), 3);
	}
}

void StartGame(int seed, int sequence_length)
{
	setrandSeed(seed);
	int i;
	for(i = 0; i < sequence_length; i++)
		{
			int r12 = rand16();
			int temp;                // temporary value set to r12 and modified to save r12
			r12 += 21845;            //

			temp = r12;                //  Generate "random" number
			temp &= 0x0fff;
			temp += TONE;
			temp %= 4;
			Play_Sound_and_LED(temp);
            toneOFF();
		}
	P4OUT &= 0xf0;
}

int ReadValues(int seed, int sequence_length)
{
	setrandSeed(seed);
	int i;
	for(i = 0; i < sequence_length; i++)
	{
		int r12 = rand16();
		int temp;                // temporary value set to r12 and modified to save r12
		r12 += 21845;            //

		temp = r12;                //  Generate "random" number
		temp &= 0x0fff;
		temp += TONE;
		temp %= 4;
		if(!VerifyCorrect(temp, getSwitch()))
		{
			return 0;
		}
	}
	return 1;
}

int VerifyCorrect(int number, int switchLED)
{
	number &= 0x000f;
	return (number == switchLED);
}

void PlayBeginningSequence()
{

	Play_Tone(NOTE_Af);
		Turn_ON_LED(R_LED);
		DelayCustom(10);
	Play_Tone(NOTE_Ef);
		Turn_ON_LED(O_LED);
		DelayCustom(20);
	Play_Tone(NOTE_Bf);
		Turn_ON_LED(Y_LED);
		DelayCustom(10);
	Play_Tone(NOTE_F);
		Turn_ON_LED(G_LED);
		DelayCustom(10);
		toneOFF;
		DelayCustom(10);
	Play_Tone(NOTE_F);
		Turn_ON_LED(R_LED);
		DelayCustom(5);
	Play_Tone(NOTE_G);
		Turn_ON_LED(O_LED);
		DelayCustom(5);
	Play_Tone(NOTE_Afh);
		Turn_ON_LED(G_LED);
		DelayCustom(30);
		toneOFF();

}

void Fanfare()
{
	Play_Tone(NOTE_C);
		Turn_ON_LED(R_LED);
		DelayCustom(3);
		toneOFF();
		DelayCustom(1);
	Play_Tone(NOTE_C);
		Turn_ON_LED(Y_LED);
		DelayCustom(3);
		toneOFF();
		DelayCustom(1);
	Play_Tone(NOTE_C);
		Turn_ON_LED(O_LED);
		DelayCustom(3);
		toneOFF();
		DelayCustom(1);
	Play_Tone(NOTE_C);
		Turn_ON_LED(G_LED);
		DelayCustom(12);
	Play_Tone(NOTE_Af);
		Turn_ON_LED(R_LED);
		DelayCustom(12);
	Play_Tone(NOTE_Bf);
		Turn_ON_LED(Y_LED);
		DelayCustom(12);
	Play_Tone(NOTE_C);
		Turn_ON_LED(G_LED);
		DelayCustom(2);
		toneOFF();
		DelayCustom(6);
	Play_Tone(NOTE_Bf);
		Turn_ON_LED(O_LED);
		DelayCustom(4);
	Play_Tone(NOTE_C);
		Turn_ON_LED(G_LED);
		DelayCustom(24);
		toneOFF();

}

void PlayRaspberrySound()
{

		int i = 0;
		for(i; i<(25*8); i++)
		{
			int j = 0;
			int k = 0;
			for (j; j<200; j++)
			Play_Tone(Rasp1);
			for (k; k<200; k++)
			Play_Tone(Rasp2);
		}
		toneOFF();
		int length = 1;
		DelayCustom(length);
		int a = 0;
		for(a; a<(70*8); a++)
		{
			int j = 0;
			int k = 0;
			for (j; j<200; j++)
			Play_Tone(Rasp1);
			for (k; k<200; k++)
			Play_Tone(Rasp2);
		}
		toneOFF();
}

void Play_Sound_and_LED(int color)
{
	switch(color)
	{
		case RED:
			Play_Tone(R_SND);
			Turn_ON_LED(R_LED);
			break;
		case YELLOW:
				Play_Tone(Y_SND);
				Turn_ON_LED(Y_LED);
				break;
		case ORANGE:
				Play_Tone(O_SND);
				Turn_ON_LED(O_LED);
				break;
		case GREEN:
				Play_Tone(G_SND);
				Turn_ON_LED(G_LED);
				break;
		default:
			break;
	}
	delay();               // Delay
    toneOFF();
	P4OUT &= 0xf0;
	DelayCustom(3);
}

//------------------------------------------------------------------------------
//   LEDs
void Turn_ON_LED (int number){
    P4OUT &= 0xf0;        // bic.w #0x0f,&P4OUT  Turn on led's
    number &= 0x0f;
    P4OUT |= number;    // bis.w r12, &P4OUT   Turn on led's based on value of number
    return;
}
/* Note: The AND with a 0xf0 and the OR with number is because a bis and bic only
 * modify the values that are changed and leave the others alone. So the And only clears
 * the last 4 bits and leaves the other bits alone, and the or will only set the bits that
 * are set in number, thereby creating a bis and bic in C.
 */

//------------------------------------------------------------------------------
//   output tone subroutine
void Play_Tone(uint16 tone)
{
    TBCCR0 = tone;                        // set beep frequency/duty cycle
    TBCCR2 = tone >> 1;                    // 50% duty cycle
    return;
} // end toneON

void toneOFF (){
    TBCCR0 = 0;                            // clear beep frequency/duty cycle
    return;
} //end ToneOFF

//------------------------------------------------------------------------------
//   Get Switch pressed using polling method
int getSwitch (){
    int button;
    	do {                                    // do-while loop used to wait until user presses switch
    	button = P1IN;
    	button &= 0x0f;
    	button ^=0x0f;
    	} while (button == 0);                    // button pressed? N-Loop

    		int button2;
    		do {
        		  DelayCustom(2);                              // do-while loop used to wait until user presses switch
    		    	button2 = P1IN;
    		    	button2 &= 0x0f;
    		    	button2 ^=0x0f;
    		   } while (button2 != 0 && button2 == button);

        switch(button)
        {
        case 1:
        	button = 0;
        	break;
        case 2:
        	button = 1;
        	break;
        case 4:
        	button = 2;
        	break;
        case 8:
        	button = 3;
        	break;
        }
        LCD_BKLT = 170*8;
    	P4OUT |= 0x10;
    	Play_Sound_and_LED(button);
    	return button;
    // y return
}

void DelayCustom (int length)
{
	 WDT_Delay = length*8;
	 __bis_SR_register(LPM0_bits + GIE);
}

void delay (){
    WDT_Delay = DELAY*8;
    __bis_SR_register(LPM0_bits + GIE);    // enable interrupts and goto sleep (LPM0)
}

//------------------------------------------------------------------------------
//    Watchdog Timer ISR
#pragma vector = WDT_VECTOR
__interrupt void WDT_ISR(void)
{
    // decrement delay (if non-zero)
    if (WDT_Delay && (--WDT_Delay == 0))    // Delay over?
    __bic_SR_register_on_exit(LPM0_bits);    // Y-Wake UP Processor

    if (--WDTSecCnt == 0)                    // WDTSecCnt 0?
    {                                        // Y-
        WDTSecCnt = WDT_IPS;                // reset counter
        LED_GREEN_TOGGLE;                    // toggle green LED
    }
    if(--LCD_BKLT <= 0)
    {
    	P4OUT &= 0xEf;
    }


} // end WDT_ISR(void)
